#include <stdint.h>
#include <stddef.h>
#include <M5GFX.h>
#include <WiFi.h>

static constexpr const uint8_t firmware_ver_major = 0;
static constexpr const uint8_t firmware_ver_minor = 0;
static constexpr const uint8_t firmware_ver_patch = 10;

static constexpr uint8_t frame_width  = 32;
static constexpr uint8_t frame_height = 24;

static constexpr inline float convertRawToCelsius(int32_t rawdata) {
    return ((float)rawdata / 128) - 64.0f;
}
static constexpr inline int32_t convertCelsiusToRaw(float temperature) {
    return (temperature + 64) * 128;
}

static constexpr const char mon_tbl[12][4] = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
static constexpr const char wday_tbl[7][4] = {
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
};

#define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(a[0]))

static constexpr const uint16_t color_map_table[][256] = {
    {
        // colormap_golden
        0x0004, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0825, 0x0825, 0x0825,
        0x0826, 0x0826, 0x0826, 0x1027, 0x1027, 0x1027, 0x1027, 0x1828, 0x1828,
        0x1848, 0x1849, 0x2049, 0x2049, 0x204A, 0x204A, 0x284A, 0x284B, 0x284B,
        0x284B, 0x306C, 0x306C, 0x306C, 0x386D, 0x386D, 0x386D, 0x408E, 0x408E,
        0x408E, 0x408F, 0x488F, 0x488F, 0x4890, 0x5090, 0x50B0, 0x50B0, 0x58B1,
        0x58B1, 0x58B1, 0x58B1, 0x60D2, 0x60D2, 0x60D2, 0x68D2, 0x68D2, 0x68D2,
        0x68F3, 0x70F3, 0x70F3, 0x70F3, 0x78F3, 0x7913, 0x7913, 0x7913, 0x8113,
        0x8133, 0x8133, 0x8133, 0x8933, 0x8932, 0x8952, 0x9152, 0x9152, 0x9152,
        0x9151, 0x9971, 0x9971, 0x9971, 0x9970, 0xA190, 0xA190, 0xA18F, 0xA98F,
        0xA9AF, 0xA9AE, 0xA9AE, 0xB1AD, 0xB1CD, 0xB1CD, 0xB9CC, 0xB9EC, 0xB9EB,
        0xB9EB, 0xC1EB, 0xC20A, 0xC20A, 0xCA09, 0xCA29, 0xCA29, 0xCA28, 0xCA28,
        0xD247, 0xD247, 0xD247, 0xDA66, 0xDA66, 0xDA65, 0xDA85, 0xDA85, 0xE284,
        0xE2A4, 0xE2A4, 0xE2A3, 0xEAC3, 0xEAC3, 0xEAE2, 0xEAE2, 0xEAE2, 0xF2E2,
        0xF301, 0xF301, 0xF321, 0xF321, 0xF321, 0xF340, 0xFB40, 0xFB40, 0xFB60,
        0xFB60, 0xFB80, 0xFB80, 0xFB80, 0xFBA0, 0xFBA0, 0xFBC0, 0xFBC0, 0xFBE0,
        0xFBE0, 0xFBE0, 0xFC00, 0xFC00, 0xFC20, 0xFC20, 0xFC40, 0xFC40, 0xFC60,
        0xFC60, 0xFC80, 0xFC80, 0xFC80, 0xFCA0, 0xFCA0, 0xFCC0, 0xFCE0, 0xFCE0,
        0xFD00, 0xFD00, 0xFD20, 0xFD20, 0xFD40, 0xFD40, 0xFD40, 0xFD60, 0xFD60,
        0xFD80, 0xFDA0, 0xFDA0, 0xFDC0, 0xFDC0, 0xFDC1, 0xFDE1, 0xFDE1, 0xFE01,
        0xFE01, 0xFE21, 0xFE21, 0xFE41, 0xFE42, 0xFE62, 0xFE62, 0xFE62, 0xFE82,
        0xFE82, 0xFE83, 0xFEA3, 0xFEA3, 0xFEC3, 0xFEC3, 0xFEC3, 0xFEE3, 0xFEE4,
        0xFEE4, 0xFF04, 0xFF04, 0xFF04, 0xFF25, 0xFF25, 0xFF25, 0xFF45, 0xFF46,
        0xFF46, 0xFF46, 0xFF67, 0xFF67, 0xFF67, 0xFF68, 0xFF68, 0xFF89, 0xFF89,
        0xFF89, 0xFF8A, 0xFF8A, 0xFFAB, 0xFFAB, 0xFFAC, 0xFFAC, 0xFFAD, 0xFFAD,
        0xFFAE, 0xFFCE, 0xFFCE, 0xFFCF, 0xFFD0, 0xFFD0, 0xFFD1, 0xFFD1, 0xFFD2,
        0xFFD2, 0xFFD3, 0xFFD3, 0xFFD4, 0xFFD4, 0xFFD5, 0xFFF5, 0xFFF6, 0xFFF6,
        0xFFF7, 0xFFF7, 0xFFF8, 0xFFF8, 0xFFF9, 0xFFF9, 0xFFF9, 0xFFFA, 0xFFFA,
        0xFFFB, 0xFFFB, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFE,
        0xFFFE, 0xFFFE, 0xFFFF, 0xFFFF,
    },
    {
        // colormap_rainbow
        0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000A,
        0x002A, 0x002B, 0x004B, 0x006B, 0x008C, 0x00AC, 0x00CC, 0x00ED, 0x010D,
        0x010E, 0x012E, 0x014E, 0x014F, 0x0170, 0x0190, 0x0190, 0x0191, 0x01B1,
        0x01B1, 0x01B1, 0x01B2, 0x01D2, 0x01D2, 0x01F3, 0x01F3, 0x0213, 0x0214,
        0x0234, 0x0234, 0x0235, 0x0255, 0x0256, 0x0276, 0x0277, 0x0277, 0x0297,
        0x0297, 0x02B8, 0x02B8, 0x02D9, 0x02D9, 0x02F9, 0x02F9, 0x02FA, 0x02FA,
        0x031A, 0x031A, 0x031A, 0x033B, 0x033B, 0x035B, 0x035B, 0x035B, 0x037B,
        0x037B, 0x039B, 0x039B, 0x03BB, 0x03BB, 0x03DB, 0x03DB, 0x03FB, 0x03FA,
        0x041A, 0x0419, 0x0439, 0x0439, 0x0438, 0x0458, 0x0457, 0x0476, 0x0C75,
        0x0C94, 0x0C94, 0x0C93, 0x0C93, 0x0C92, 0x0CB1, 0x14B0, 0x14CF, 0x1CCE,
        0x1CED, 0x24EC, 0x2D0B, 0x2D0A, 0x3529, 0x3D28, 0x4547, 0x4D66, 0x4D66,
        0x5585, 0x5D84, 0x5DA4, 0x65A3, 0x6DC3, 0x6DC2, 0x75E2, 0x75E2, 0x7DE2,
        0x8601, 0x8601, 0x8E21, 0x8E21, 0x9620, 0x9640, 0x9E40, 0xA640, 0xA660,
        0xAE60, 0xAE60, 0xAE60, 0xB660, 0xBE80, 0xBE80, 0xC680, 0xC6A0, 0xC6A0,
        0xCEA0, 0xCEA0, 0xD6A0, 0xD6A0, 0xDEA0, 0xDEA0, 0xDEA0, 0xE6A0, 0xE6A0,
        0xE6A0, 0xE680, 0xEE80, 0xEE80, 0xEE80, 0xEE80, 0xEE80, 0xEE80, 0xEE81,
        0xEE61, 0xF661, 0xF641, 0xF641, 0xF641, 0xF641, 0xF621, 0xF621, 0xF621,
        0xFE01, 0xFDE1, 0xFDE1, 0xFDC1, 0xFDC2, 0xFDA2, 0xFD82, 0xFD62, 0xFD42,
        0xFD42, 0xFD22, 0xFD22, 0xFD02, 0xFD02, 0xFCE2, 0xFCE2, 0xFCC3, 0xFCA3,
        0xFC63, 0xFC43, 0xFC23, 0xFC03, 0xFBE4, 0xFBA4, 0xFB64, 0xFB44, 0xFB24,
        0xFB04, 0xFAE5, 0xFAC5, 0xFA85, 0xFA65, 0xFA25, 0xF9E6, 0xF9C6, 0xF9A6,
        0xF986, 0xF966, 0xF927, 0xF907, 0xF907, 0xF8E7, 0xF8E7, 0xF8E7, 0xF8E7,
        0xF8C7, 0xF8C8, 0xF8C8, 0xF8C8, 0xF8C8, 0xF8C9, 0xF0C9, 0xF0C9, 0xF0C9,
        0xF0CA, 0xF10A, 0xF10A, 0xF12A, 0xF14B, 0xF16B, 0xF18B, 0xF9AB, 0xF9CC,
        0xFA0C, 0xFA4C, 0xFA8D, 0xFAAD, 0xFAED, 0xFAED, 0xFB0D, 0xFB2D, 0xFB2E,
        0xFB2E, 0xFB6E, 0xFBAF, 0xFBCF, 0xFBEF, 0xFC10, 0xFC30, 0xFC50, 0xFC91,
        0xFCB1, 0xFCF2, 0xFD12, 0xFD52, 0xFD73, 0xFD93, 0xFD93, 0xFDD4, 0xFDF4,
        0xFE15, 0xFE35, 0xFE55, 0xFE76, 0xFE96, 0xFED7, 0xFED7, 0xFEF8, 0xFEF9,
        0xFF19, 0xFF19, 0xFF39, 0xFF5A,
    },
    {
        // colormap_grayscale
        0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0020, 0x0820, 0x0820, 0x0840,
        0x0840, 0x0841, 0x0841, 0x0861, 0x0861, 0x1061, 0x1061, 0x1081, 0x1081,
        0x1082, 0x1082, 0x10a2, 0x10a2, 0x18a2, 0x18a2, 0x18c2, 0x18c2, 0x18c3,
        0x18c3, 0x18e3, 0x18e3, 0x20e3, 0x20e3, 0x2103, 0x2103, 0x2104, 0x2104,
        0x2124, 0x2124, 0x2924, 0x2924, 0x2944, 0x2944, 0x2945, 0x2945, 0x2965,
        0x2965, 0x3165, 0x3165, 0x3185, 0x3185, 0x3186, 0x3186, 0x31a6, 0x31a6,
        0x39a6, 0x39a6, 0x39c6, 0x39c6, 0x39c7, 0x39c7, 0x39e7, 0x39e7, 0x41e7,
        0x41e7, 0x4207, 0x4207, 0x4208, 0x4208, 0x4228, 0x4228, 0x4a28, 0x4a28,
        0x4a48, 0x4a48, 0x4a49, 0x4a49, 0x4a69, 0x4a69, 0x5269, 0x5269, 0x5289,
        0x5289, 0x528a, 0x528a, 0x52aa, 0x52aa, 0x5aaa, 0x5aaa, 0x5aca, 0x5aca,
        0x5acb, 0x5acb, 0x5aeb, 0x5aeb, 0x62eb, 0x62eb, 0x630b, 0x630b, 0x630c,
        0x630c, 0x632c, 0x632c, 0x6b2c, 0x6b2c, 0x6b4c, 0x6b4c, 0x6b4d, 0x6b4d,
        0x6b6d, 0x6b6d, 0x736d, 0x736d, 0x738d, 0x738d, 0x738e, 0x738e, 0x73ae,
        0x73ae, 0x7bae, 0x7bae, 0x7bce, 0x7bce, 0x7bcf, 0x7bcf, 0x7bef, 0x7bef,
        0x83ef, 0x83ef, 0x840f, 0x840f, 0x8410, 0x8410, 0x8430, 0x8430, 0x8c30,
        0x8c30, 0x8c50, 0x8c50, 0x8c51, 0x8c51, 0x8c71, 0x8c71, 0x9471, 0x9471,
        0x9491, 0x9491, 0x9492, 0x9492, 0x94b2, 0x94b2, 0x9cb2, 0x9cb2, 0x9cd2,
        0x9cd2, 0x9cd3, 0x9cd3, 0x9cf3, 0x9cf3, 0xa4f3, 0xa4f3, 0xa513, 0xa513,
        0xa514, 0xa514, 0xa534, 0xa534, 0xad34, 0xad34, 0xad54, 0xad54, 0xad55,
        0xad55, 0xad75, 0xad75, 0xb575, 0xb575, 0xb595, 0xb595, 0xb596, 0xb596,
        0xb5b6, 0xb5b6, 0xbdb6, 0xbdb6, 0xbdd6, 0xbdd6, 0xbdd7, 0xbdd7, 0xbdf7,
        0xbdf7, 0xc5f7, 0xc5f7, 0xc617, 0xc617, 0xc618, 0xc618, 0xc638, 0xc638,
        0xce38, 0xce38, 0xce58, 0xce58, 0xce59, 0xce59, 0xce79, 0xce79, 0xd679,
        0xd679, 0xd699, 0xd699, 0xd69a, 0xd69a, 0xd6ba, 0xd6ba, 0xdeba, 0xdeba,
        0xdeda, 0xdeda, 0xdedb, 0xdedb, 0xdefb, 0xdefb, 0xe6fb, 0xe6fb, 0xe71b,
        0xe71b, 0xe71c, 0xe71c, 0xe73c, 0xe73c, 0xef3c, 0xef3c, 0xef5c, 0xef5c,
        0xef5d, 0xef5d, 0xef7d, 0xef7d, 0xf77d, 0xf77d, 0xf79d, 0xf79d, 0xf79e,
        0xf79e, 0xf7be, 0xf7be, 0xffbe, 0xffbe, 0xffde, 0xffde, 0xffdf, 0xffdf,
        0xffff, 0xffff, 0xffff, 0xffff,
    },
    {
        // colormap_ironblack
        0xFFFF, 0xFFFF, 0xFFDF, 0xFFDF, 0xF7BE, 0xF7BE, 0xF79E, 0xF79E, 0xEF7D,
        0xEF7D, 0xEF5D, 0xEF5D, 0xE73C, 0xE73C, 0xE71C, 0xE71C, 0xDEFB, 0xDEFB,
        0xDEDB, 0xDEDB, 0xD6BA, 0xD6BA, 0xD69A, 0xD69A, 0xCE79, 0xCE79, 0xCE59,
        0xCE59, 0xC638, 0xC638, 0xC618, 0xC618, 0xBDF7, 0xBDF7, 0xBDD7, 0xBDD7,
        0xB5B6, 0xB5B6, 0xB596, 0xB596, 0xAD75, 0xAD75, 0xAD55, 0xAD55, 0xA534,
        0xA534, 0xA514, 0xA514, 0x9CF3, 0x9CF3, 0x9CD3, 0x9CD3, 0x94B2, 0x94B2,
        0x9492, 0x9492, 0x8C71, 0x8C71, 0x8C51, 0x8C51, 0x8430, 0x8430, 0x8410,
        0x8410, 0x7BEF, 0x7BEF, 0x7BCF, 0x7BCF, 0x73AE, 0x73AE, 0x738E, 0x738E,
        0x6B6D, 0x6B6D, 0x6B4D, 0x6B4D, 0x632C, 0x632C, 0x630C, 0x630C, 0x5AEB,
        0x5AEB, 0x5ACB, 0x5ACB, 0x52AA, 0x52AA, 0x528A, 0x528A, 0x4A69, 0x4A69,
        0x4A49, 0x4A49, 0x4228, 0x4228, 0x4208, 0x4208, 0x39E7, 0x39E7, 0x39C7,
        0x39C7, 0x31A6, 0x31A6, 0x3186, 0x3186, 0x2965, 0x2965, 0x2945, 0x2945,
        0x2124, 0x2124, 0x2104, 0x2104, 0x18E3, 0x18E3, 0x18C3, 0x18C3, 0x10A2,
        0x10A2, 0x1082, 0x1082, 0x0861, 0x0861, 0x0841, 0x0841, 0x0020, 0x0020,
        0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0003, 0x0804, 0x0805, 0x0806,
        0x0807, 0x1008, 0x1009, 0x100A, 0x100B, 0x180C, 0x180C, 0x180D, 0x180E,
        0x200F, 0x280F, 0x280F, 0x300F, 0x380F, 0x380F, 0x400F, 0x400F, 0x4810,
        0x5010, 0x5010, 0x5810, 0x6010, 0x6010, 0x6810, 0x6810, 0x7011, 0x7811,
        0x7811, 0x8011, 0x8011, 0x8811, 0x9011, 0x9031, 0x9831, 0x9831, 0xA031,
        0xA031, 0xA831, 0xB031, 0xB031, 0xB831, 0xB851, 0xB870, 0xC08F, 0xC08F,
        0xC0AE, 0xC8CD, 0xC8ED, 0xC8EC, 0xC90B, 0xD12B, 0xD14A, 0xD14A, 0xD969,
        0xD988, 0xD9A8, 0xD9A7, 0xE1C6, 0xE1E5, 0xE205, 0xE205, 0xE224, 0xE244,
        0xE264, 0xE284, 0xE2A3, 0xEAC3, 0xEAE3, 0xEAE2, 0xEB02, 0xEB22, 0xEB41,
        0xEB61, 0xEB81, 0xF3A1, 0xF3A1, 0xF3C1, 0xF3E1, 0xF401, 0xF421, 0xF441,
        0xF461, 0xF481, 0xF4A1, 0xF4C1, 0xF4E1, 0xF501, 0xF501, 0xF521, 0xF541,
        0xFD61, 0xFD81, 0xFDA2, 0xFDC2, 0xFDE2, 0xFE02, 0xFE22, 0xFE22, 0xFE42,
        0xFE63, 0xFE83, 0xFEA3, 0xFEC3, 0xFEE3, 0xFF03, 0xFF04, 0xFF26, 0xFF28,
        0xFF4A, 0xFF4B, 0xFF6D, 0xFF6F, 0xFF91, 0xFF92, 0xFFB4, 0xFFB6, 0xFFD8,
        0xFFD9, 0xFFDB, 0xFFFD, 0xFFE3,
    },
    {
        // colormap_cam
        0x480F, 0x400F, 0x400F, 0x400F, 0x4010, 0x3810, 0x3810, 0x3810, 0x3810,
        0x3010, 0x3010, 0x3010, 0x2810, 0x2810, 0x2810, 0x2810, 0x2010, 0x2010,
        0x2010, 0x1810, 0x1810, 0x1811, 0x1811, 0x1011, 0x1011, 0x1011, 0x0811,
        0x0811, 0x0811, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0031, 0x0031,
        0x0051, 0x0072, 0x0072, 0x0092, 0x00B2, 0x00B2, 0x00D2, 0x00F2, 0x00F2,
        0x0112, 0x0132, 0x0152, 0x0152, 0x0172, 0x0192, 0x0192, 0x01B2, 0x01D2,
        0x01F3, 0x01F3, 0x0213, 0x0233, 0x0253, 0x0253, 0x0273, 0x0293, 0x02B3,
        0x02D3, 0x02D3, 0x02F3, 0x0313, 0x0333, 0x0333, 0x0353, 0x0373, 0x0394,
        0x03B4, 0x03D4, 0x03D4, 0x03F4, 0x0414, 0x0434, 0x0454, 0x0474, 0x0474,
        0x0494, 0x04B4, 0x04D4, 0x04F4, 0x0514, 0x0534, 0x0534, 0x0554, 0x0554,
        0x0574, 0x0574, 0x0573, 0x0573, 0x0573, 0x0572, 0x0572, 0x0572, 0x0571,
        0x0591, 0x0591, 0x0590, 0x0590, 0x058F, 0x058F, 0x058F, 0x058E, 0x05AE,
        0x05AE, 0x05AD, 0x05AD, 0x05AD, 0x05AC, 0x05AC, 0x05AB, 0x05CB, 0x05CB,
        0x05CA, 0x05CA, 0x05CA, 0x05C9, 0x05C9, 0x05C8, 0x05E8, 0x05E8, 0x05E7,
        0x05E7, 0x05E6, 0x05E6, 0x05E6, 0x05E5, 0x05E5, 0x0604, 0x0604, 0x0604,
        0x0603, 0x0603, 0x0602, 0x0602, 0x0601, 0x0621, 0x0621, 0x0620, 0x0620,
        0x0620, 0x0620, 0x0E20, 0x0E20, 0x0E40, 0x1640, 0x1640, 0x1E40, 0x1E40,
        0x2640, 0x2640, 0x2E40, 0x2E60, 0x3660, 0x3660, 0x3E60, 0x3E60, 0x3E60,
        0x4660, 0x4660, 0x4E60, 0x4E80, 0x5680, 0x5680, 0x5E80, 0x5E80, 0x6680,
        0x6680, 0x6E80, 0x6EA0, 0x76A0, 0x76A0, 0x7EA0, 0x7EA0, 0x86A0, 0x86A0,
        0x8EA0, 0x8EC0, 0x96C0, 0x96C0, 0x9EC0, 0x9EC0, 0xA6C0, 0xAEC0, 0xAEC0,
        0xB6E0, 0xB6E0, 0xBEE0, 0xBEE0, 0xC6E0, 0xC6E0, 0xCEE0, 0xCEE0, 0xD6E0,
        0xD700, 0xDF00, 0xDEE0, 0xDEC0, 0xDEA0, 0xDE80, 0xDE80, 0xE660, 0xE640,
        0xE620, 0xE600, 0xE5E0, 0xE5C0, 0xE5A0, 0xE580, 0xE560, 0xE540, 0xE520,
        0xE500, 0xE4E0, 0xE4C0, 0xE4A0, 0xE480, 0xE460, 0xEC40, 0xEC20, 0xEC00,
        0xEBE0, 0xEBC0, 0xEBA0, 0xEB80, 0xEB60, 0xEB40, 0xEB20, 0xEB00, 0xEAE0,
        0xEAC0, 0xEAA0, 0xEA80, 0xEA60, 0xEA40, 0xF220, 0xF200, 0xF1E0, 0xF1C0,
        0xF1A0, 0xF180, 0xF160, 0xF140, 0xF100, 0xF0E0, 0xF0C0, 0xF0A0, 0xF080,
        0xF060, 0xF040, 0xF020, 0xF800,
    }};

static constexpr const size_t color_map_table_len =
    SIZEOF_ARRAY(color_map_table);

static constexpr const lgfx::swap565_t icon_cloud565[][16 * 14] = {
    {
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x031b, 0xaa54, 0x4d6d, 0xaa54, 0x031b, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xaa54, 0x1086, 0xf085, 0x4d6d, 0xf085, 0x1086, 0xaa54, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xa633, 0x1086, 0x694c,
        0x2002, 0x2002, 0x2002, 0x694c, 0x1086, 0xa633, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0xcf7d, 0x4d6d, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x4d6d, 0xcf7d, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x4002, 0x694c, 0x1086, 0xe73b, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xe73b, 0x1086, 0x694c, 0x4002, 0x2002, 0x2002, 0x2002, 0xae75, 0x1086,
        0x0c65, 0x852b, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x852b, 0x0c65,
        0x1086, 0xae75, 0x2002, 0x2002, 0xc633, 0x1086, 0xc212, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xc212, 0x1086,
        0xc633, 0x2002, 0x494c, 0x1086, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x1086, 0x494c, 0x2002,
        0x031b, 0x1086, 0x694c, 0x4002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x4002, 0x694c, 0x1086, 0x031b, 0x2002, 0x2002, 0x494c,
        0x1086, 0x1086, 0x1086, 0x2002, 0x4002, 0x210e, 0x4002, 0x2002, 0x1086,
        0x1086, 0x1086, 0x494c, 0x2002, 0x2002, 0x2002, 0x2002, 0x810a, 0x652b,
        0x652b, 0x4002, 0x010f, 0xe217, 0x010f, 0x4002, 0x652b, 0x652b, 0x810a,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xa002,
        0x2003, 0xe217, 0x2003, 0xa002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xe217,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x031b, 0xaa54, 0x4d6d, 0xaa54, 0x031b, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xaa54, 0x1086, 0xf085, 0x4d6d, 0xf085, 0x1086, 0xaa54, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xa633, 0x1086, 0x694c,
        0x2002, 0x2002, 0x2002, 0x694c, 0x1086, 0xa633, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0xcf7d, 0x4d6d, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x4d6d, 0xcf7d, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x4002, 0x694c, 0x1086, 0xe73b, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xe73b, 0x1086, 0x694c, 0x4002, 0x2002, 0x2002, 0x2002, 0xae75, 0x1086,
        0x0c65, 0x852b, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x852b, 0x0c65,
        0x1086, 0xae75, 0x2002, 0x2002, 0xc633, 0x1086, 0xc212, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xc212, 0x1086,
        0xc633, 0x2002, 0x494c, 0x1086, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x1086, 0x494c, 0x2002,
        0x031b, 0x1086, 0x694c, 0x4002, 0x2002, 0x2002, 0x2002, 0x610d, 0x2002,
        0x2002, 0x2002, 0x4002, 0x694c, 0x1086, 0x031b, 0x2002, 0x2002, 0x494c,
        0x1086, 0x1086, 0x1086, 0x2002, 0x810e, 0xe217, 0x810e, 0x2002, 0x1086,
        0x1086, 0x1086, 0x494c, 0x2002, 0x2002, 0x2002, 0x2002, 0x810a, 0x652b,
        0x652b, 0xe002, 0xe003, 0xe217, 0xe003, 0xe002, 0x652b, 0x652b, 0x810a,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0xe217, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xe217,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x031b, 0xaa54, 0x4d6d, 0xaa54, 0x031b, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xaa54, 0x1086, 0xf085, 0x4d6d, 0xf085, 0x1086, 0xaa54, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xa633, 0x1086, 0x694c,
        0x2002, 0x2002, 0x2002, 0x694c, 0x1086, 0xa633, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0xcf7d, 0x4d6d, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x4d6d, 0xcf7d, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x4002, 0x694c, 0x1086, 0xe73b, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xe73b, 0x1086, 0x694c, 0x4002, 0x2002, 0x2002, 0x2002, 0xae75, 0x1086,
        0x0c65, 0x852b, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x852b, 0x0c65,
        0x1086, 0xae75, 0x2002, 0x2002, 0xc633, 0x1086, 0xc212, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xc212, 0x1086,
        0xc633, 0x2002, 0x494c, 0x1086, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xa004, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x1086, 0x494c, 0x2002,
        0x031b, 0x1086, 0x694c, 0x4002, 0x2002, 0x2002, 0x010e, 0xe217, 0x010e,
        0x2002, 0x2002, 0x4002, 0x694c, 0x1086, 0x031b, 0x2002, 0x2002, 0x494c,
        0x1086, 0x1086, 0x1086, 0x2003, 0xa004, 0xe217, 0xa004, 0x2003, 0x1086,
        0x1086, 0x1086, 0x494c, 0x2002, 0x2002, 0x2002, 0x2002, 0x810a, 0x652b,
        0x652b, 0x2002, 0x2002, 0xe217, 0x2002, 0x2002, 0x652b, 0x652b, 0x810a,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0xe217, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xe003,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x031b, 0xaa54, 0x4d6d, 0xaa54, 0x031b, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xaa54, 0x1086, 0xf085, 0x4d6d, 0xf085, 0x1086, 0xaa54, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xa633, 0x1086, 0x694c,
        0x2002, 0x2002, 0x2002, 0x694c, 0x1086, 0xa633, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0xcf7d, 0x4d6d, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x4d6d, 0xcf7d, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x4002, 0x694c, 0x1086, 0xe73b, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xe73b, 0x1086, 0x694c, 0x4002, 0x2002, 0x2002, 0x2002, 0xae75, 0x1086,
        0x0c65, 0x852b, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x852b, 0x0c65,
        0x1086, 0xae75, 0x2002, 0x2002, 0xc633, 0x1086, 0xc212, 0x2002, 0x2002,
        0x2002, 0x2002, 0xe003, 0x2002, 0x2002, 0x2002, 0x2002, 0xc212, 0x1086,
        0xc633, 0x2002, 0x494c, 0x1086, 0x2002, 0x2002, 0x2002, 0x2002, 0x610d,
        0xe217, 0x610d, 0x2002, 0x2002, 0x2002, 0x2002, 0x1086, 0x494c, 0x2002,
        0x031b, 0x1086, 0x694c, 0x4002, 0x2002, 0x4003, 0x610d, 0xe217, 0x610d,
        0x4003, 0x2002, 0x4002, 0x694c, 0x1086, 0x031b, 0x2002, 0x2002, 0x494c,
        0x1086, 0x1086, 0x1086, 0x2002, 0x2002, 0xe217, 0x2002, 0x2002, 0x1086,
        0x1086, 0x1086, 0x494c, 0x2002, 0x2002, 0x2002, 0x2002, 0x810a, 0x652b,
        0x652b, 0x2002, 0x2002, 0xe217, 0x2002, 0x2002, 0x652b, 0x652b, 0x810a,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0xa004, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x4633, 0xb39d, 0x78c6, 0xb39d, 0x4633, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x7295, 0x7def, 0x5def, 0x78c6, 0x5def, 0x7def, 0x7295, 0x6002, 0xc002,
        0x6002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2b5c, 0x7def, 0x3085,
        0x2002, 0x2002, 0x2002, 0x3085, 0x9bdf, 0xa426, 0x0006, 0x4003, 0x2002,
        0x2002, 0x2002, 0x4002, 0xe002, 0x19cf, 0x78c6, 0x2002, 0x2002, 0x2002,
        0x2002, 0x8002, 0x694f, 0xa847, 0xe005, 0x8002, 0x2002, 0x2002, 0x2002,
        0xe002, 0x052f, 0xca57, 0xaa54, 0x2002, 0x2002, 0x2002, 0x8002, 0xc005,
        0xc426, 0xca57, 0xb18d, 0x610a, 0x2002, 0x2002, 0x4002, 0xf9ce, 0xcb5f,
        0x473f, 0x831e, 0xc002, 0x2002, 0x8002, 0xc005, 0x0006, 0x831e, 0x339e,
        0x7def, 0xfad6, 0x4002, 0x2002, 0x4c64, 0x7def, 0x452b, 0xc005, 0x0006,
        0xe005, 0x2003, 0xc005, 0x0006, 0xe005, 0xa002, 0x2002, 0x052b, 0x7def,
        0x4c64, 0x2002, 0x1085, 0x7def, 0x2002, 0x6002, 0xc005, 0x0006, 0x2007,
        0x2006, 0xe005, 0xa002, 0x2002, 0x2002, 0x2002, 0x7def, 0x1085, 0x2002,
        0x673b, 0x7def, 0x318d, 0x410a, 0x6002, 0xe005, 0x6007, 0x4006, 0xa002,
        0x2002, 0x2002, 0x410a, 0x518d, 0x7def, 0x673b, 0x2002, 0x2002, 0x1085,
        0x7def, 0x7def, 0x7def, 0x7ce7, 0x9ad7, 0x7ce7, 0x7def, 0x7def, 0x7def,
        0x7def, 0x7def, 0x1085, 0x2002, 0x2002, 0x2002, 0x2002, 0xa212, 0xc94b,
        0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xa212,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x4093, 0x00fc, 0x00fc, 0x00fc, 0x4093, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x0002, 0xe021,
        0x80e3, 0x00fc, 0x60ab, 0xe06a, 0x60ab, 0x00fc, 0xa0e3, 0xe021, 0x000a,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xe019, 0x00d9, 0x60f9, 0x4052,
        0x2002, 0x2002, 0x2002, 0x604a, 0x60f9, 0x00d1, 0xa031, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x000a, 0x80f9, 0x20e1, 0xa0a0, 0xe019, 0x2002,
        0x0012, 0xc0a0, 0x20e1, 0x60f9, 0xe011, 0x2002, 0x2002, 0x2002, 0x2002,
        0x803a, 0xe0eb, 0xc0fb, 0x20c9, 0xa0a8, 0xa0a0, 0xc029, 0xc0a0, 0xa0a8,
        0x00c9, 0xa0fb, 0xe0eb, 0x803a, 0x2002, 0x2002, 0x401a, 0x00fc, 0xc0db,
        0xc05a, 0x603a, 0xc098, 0xa0a8, 0x40d8, 0xa0b0, 0xc0a0, 0x4042, 0xc05a,
        0xc0db, 0x00fc, 0x401a, 0x2002, 0x0083, 0x00fc, 0x2002, 0x2002, 0x2002,
        0xe019, 0x40d8, 0x20e0, 0x20e0, 0xa031, 0x2002, 0x2002, 0x2002, 0x00fc,
        0x0083, 0x2002, 0x0083, 0x00fc, 0x2002, 0x2002, 0x0012, 0xc0a0, 0xa0a8,
        0x40e0, 0xa0b0, 0xa0a0, 0xe019, 0x2002, 0x2002, 0x00fc, 0x0083, 0x2002,
        0x401a, 0x00fc, 0xc0db, 0x8062, 0xe0b8, 0xe0c0, 0x00c1, 0x6072, 0x00c1,
        0xe0c0, 0xe0c0, 0x6062, 0xc0db, 0x00fc, 0x401a, 0x2002, 0x2002, 0x803a,
        0xa0eb, 0x60f9, 0x40f9, 0x60f9, 0xa0fb, 0x00fc, 0xc0fb, 0x80f9, 0x40f9,
        0x60f9, 0x80eb, 0x803a, 0x2002, 0x2002, 0x2002, 0x2002, 0xe021, 0xa0a8,
        0xc0a0, 0xe011, 0x2002, 0x2002, 0x2002, 0x000a, 0xc098, 0xa0a8, 0xa031,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x0002, 0xe011, 0x000a, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x0002, 0xe011, 0x0002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x4633, 0xb39d, 0x78c6, 0xb39d, 0x4633, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x7295, 0x7def, 0x5def, 0x78c6, 0x5def, 0x7def, 0x7295, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2b5c, 0x7def, 0x3085,
        0x2002, 0x2002, 0x2002, 0x3085, 0x7def, 0x2b5c, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x1bdf, 0x78c6, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x78c6, 0x1bdf, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x610a, 0x318d, 0x7def, 0x8d6c, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x8d6c, 0x7def, 0x318d, 0x610a, 0x2002, 0x2002, 0x4002, 0xfad6, 0x7def,
        0x36b6, 0x0a54, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x0a54, 0x36b6,
        0x7def, 0xfad6, 0x4002, 0x2002, 0x4c64, 0x7def, 0x052b, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x052b, 0x7def,
        0x4c64, 0x2002, 0x1085, 0x7def, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x7def, 0x1085, 0x2002,
        0x673b, 0x7def, 0x318d, 0x410a, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x410a, 0x518d, 0x7def, 0x673b, 0x2002, 0x2002, 0x1085,
        0x7def, 0x7def, 0x7def, 0x7def, 0x7def, 0x7def, 0x7def, 0x7def, 0x7def,
        0x7def, 0x7def, 0x1085, 0x2002, 0x2002, 0x2002, 0x2002, 0xa212, 0xc94b,
        0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xc94b, 0xa212,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
    },
};

static constexpr const lgfx::swap565_t icon_wifi565[][16 * 14] = {
    {
        0x2002, 0x2002, 0x6112, 0x6112, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xe642,
        0xe5a9, 0x84b9, 0x097b, 0x6a6b, 0x074b, 0x621a, 0x2002, 0x0012, 0xe088,
        0x0081, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x400a, 0x2199, 0xc1b0,
        0xe1b8, 0xc762, 0x6a6b, 0x6a6b, 0xe862, 0xc0a0, 0xa0a8, 0xc098, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x000a, 0xc098, 0xa0a8, 0xa0a0,
        0xe019, 0x8442, 0x43c9, 0x23c9, 0xe1b0, 0xe011, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0xa42a, 0x6a6b, 0x2973, 0x43c1, 0x02c1, 0xc0b0, 0xa0a8,
        0xc0a8, 0x23c1, 0x2973, 0x8322, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x410a, 0xc53a, 0xe63a, 0xe75a, 0x23c9, 0x61e8, 0x60e8, 0xa0a8, 0x0012,
        0x495b, 0x6a6b, 0x410a, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x0012, 0xc0a0, 0x40e0, 0x61e8, 0x02c1, 0xe019, 0x400a, 0x6a6b,
        0x285b, 0x2002, 0x2002, 0x2002, 0x2002, 0x821a, 0x495b, 0x086b, 0x02b9,
        0xc0a8, 0xa0a8, 0xe1b0, 0x23c9, 0x02b9, 0xe019, 0xa432, 0x6a6b, 0x621a,
        0x2002, 0x2002, 0x2002, 0x821a, 0xe862, 0x23c1, 0x23c9, 0x23c9, 0x6332,
        0x000a, 0x02b1, 0x23c9, 0xc0a8, 0xe019, 0x6a6b, 0x074b, 0x2002, 0x2002,
        0x2002, 0x2002, 0x0089, 0xa0a8, 0xc0a0, 0x086b, 0x6a6b, 0x410a, 0x000a,
        0x43c1, 0x02c1, 0xc098, 0x074b, 0x6a6b, 0x2002, 0x2002, 0x2002, 0x2002,
        0x20c2, 0xe0d9, 0x001a, 0x410a, 0x6a6b, 0xe642, 0x2002, 0xe75a, 0xa5b1,
        0x2079, 0xc432, 0x6a6b, 0x2002, 0x2002, 0x2002, 0x608b, 0x80fc, 0x80fc,
        0x608b, 0x2002, 0x285b, 0x4963, 0x2002, 0xe63a, 0x6a6b, 0x2002, 0x8322,
        0x6a6b, 0x6112, 0x2002, 0x2002, 0x608b, 0x80fc, 0x80fc, 0x608b, 0x2002,
        0x2853, 0x495b, 0x2002, 0xc53a, 0x6a6b, 0x2002, 0x8322, 0x6a6b, 0x6112,
        0x2002, 0x2002, 0x2002, 0x608b, 0x608b, 0x2002, 0x2002, 0x821a, 0x821a,
        0x2002, 0x410a, 0xa42a, 0x2002, 0x400a, 0xe642, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x6112, 0x6112, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xe642,
        0x6a6b, 0x6a6b, 0x6a6b, 0x6a6b, 0x074b, 0x621a, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x400a, 0x8322, 0x8322,
        0xc432, 0x074b, 0x6a6b, 0x6a6b, 0x285b, 0x410a, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0xa432, 0x6a6b, 0x6a6b, 0x8322, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0xa42a, 0x6a6b, 0x6a6b, 0x496b, 0x074b, 0x4112, 0x2002,
        0x400a, 0x495b, 0x6a6b, 0x8322, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x410a, 0xc53a, 0xe63a, 0x2853, 0x6a6b, 0x6a6b, 0x074b, 0x2002, 0x2002,
        0x495b, 0x6a6b, 0x410a, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0xe642, 0x6a6b, 0x285b, 0x2002, 0x400a, 0x6a6b,
        0x285b, 0x2002, 0x2002, 0x2002, 0x2002, 0x821a, 0x495b, 0x4963, 0xe642,
        0x410a, 0x2002, 0xa42a, 0x6a6b, 0x074b, 0x2002, 0xa432, 0x6a6b, 0x621a,
        0x2002, 0x2002, 0x2002, 0x821a, 0x2853, 0x285b, 0x6a6b, 0x6a6b, 0x8322,
        0x2002, 0xe642, 0x6a6b, 0x4112, 0x2002, 0x6a6b, 0x074b, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x410a, 0x4963, 0x6a6b, 0x410a, 0x2002,
        0x6a6b, 0x074b, 0x2002, 0x074b, 0x6a6b, 0x2002, 0x2002, 0x2002, 0x2002,
        0x608b, 0x608b, 0x2002, 0x410a, 0x6a6b, 0xe642, 0x2002, 0x2853, 0x496b,
        0x2002, 0xc432, 0x6a6b, 0x2002, 0x2002, 0x2002, 0x608b, 0x80fc, 0x80fc,
        0x608b, 0x2002, 0x285b, 0x4963, 0x2002, 0xe63a, 0x6a6b, 0x2002, 0x8322,
        0x6a6b, 0x6112, 0x2002, 0x2002, 0x608b, 0x80fc, 0x80fc, 0x608b, 0x2002,
        0x2853, 0x495b, 0x2002, 0xc53a, 0x6a6b, 0x2002, 0x8322, 0x6a6b, 0x6112,
        0x2002, 0x2002, 0x2002, 0x608b, 0x608b, 0x2002, 0x2002, 0x821a, 0x821a,
        0x2002, 0x410a, 0xa42a, 0x2002, 0x400a, 0xe642, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x6112, 0x6112, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xe642,
        0x6a6b, 0x6a6b, 0x6a6b, 0x6a6b, 0x074b, 0x621a, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x400a, 0x8322, 0x8322,
        0xc432, 0x074b, 0x6a6b, 0x6a6b, 0x285b, 0x410a, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0xa432, 0x6a6b, 0x6a6b, 0x8322, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0xa42a, 0x6a6b, 0x6a6b, 0x496b, 0x074b, 0x4112, 0x2002,
        0x400a, 0x495b, 0x6a6b, 0x8322, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x410a, 0xc53a, 0xe63a, 0x2853, 0x6a6b, 0x6a6b, 0x074b, 0x2002, 0x2002,
        0x495b, 0x6a6b, 0x410a, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0xe642, 0x6a6b, 0x285b, 0x2002, 0x400a, 0x6a6b,
        0x285b, 0x2002, 0x2002, 0x2002, 0x2002, 0x821a, 0x495b, 0x4963, 0xe642,
        0x410a, 0x2002, 0xa42a, 0x6a6b, 0x074b, 0x2002, 0xa432, 0x6a6b, 0x621a,
        0x2002, 0x2002, 0x2002, 0x821a, 0x2853, 0x285b, 0x6a6b, 0x6a6b, 0x8322,
        0x2002, 0xe642, 0x6a6b, 0x4112, 0x2002, 0x6a6b, 0x074b, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x410a, 0x4963, 0x6a6b, 0x410a, 0x2002,
        0x6a6b, 0x074b, 0x2002, 0x074b, 0x6a6b, 0x2002, 0x2002, 0x2002, 0x2002,
        0xd17c, 0xd17c, 0x2002, 0x410a, 0x6a6b, 0xe642, 0x2002, 0x2853, 0x496b,
        0x2002, 0xc432, 0x6a6b, 0x2002, 0x2002, 0x2002, 0xd17c, 0xdfde, 0xdfde,
        0xd17c, 0x2002, 0x285b, 0x4963, 0x2002, 0xe63a, 0x6a6b, 0x2002, 0x8322,
        0x6a6b, 0x6112, 0x2002, 0x2002, 0xd17c, 0xdfde, 0xdfde, 0xd17c, 0x2002,
        0x2853, 0x495b, 0x2002, 0xc53a, 0x6a6b, 0x2002, 0x8322, 0x6a6b, 0x6112,
        0x2002, 0x2002, 0x2002, 0xd17c, 0xd17c, 0x2002, 0x2002, 0x821a, 0x821a,
        0x2002, 0x410a, 0xa42a, 0x2002, 0x400a, 0xe642, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x6112, 0x6112, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xe642,
        0x6a6b, 0x6a6b, 0x6a6b, 0x6a6b, 0x074b, 0x621a, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x400a, 0x8322, 0x8322,
        0xc432, 0x074b, 0x6a6b, 0x6a6b, 0x285b, 0x410a, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0xa432, 0x6a6b, 0x6a6b, 0x8322, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0xa42a, 0x6a6b, 0x6a6b, 0x496b, 0x074b, 0x4112, 0x2002,
        0x400a, 0x495b, 0x6a6b, 0x8322, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x410a, 0xc53a, 0xe63a, 0x2853, 0x6a6b, 0x6a6b, 0x074b, 0x2002, 0x2002,
        0x495b, 0x6a6b, 0x410a, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0xe642, 0x6a6b, 0x285b, 0x2002, 0x400a, 0x6a6b,
        0x285b, 0x2002, 0x2002, 0x2002, 0x2002, 0x683b, 0x5cc6, 0x5cc6, 0x138d,
        0xa31a, 0x2002, 0xa42a, 0x6a6b, 0x074b, 0x2002, 0xa432, 0x6a6b, 0x621a,
        0x2002, 0x2002, 0x2002, 0x683b, 0xf9b5, 0x3bc6, 0xdfde, 0xdfde, 0xaa4b,
        0x2002, 0xe642, 0x6a6b, 0x4112, 0x2002, 0x6a6b, 0x074b, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x8312, 0x7cce, 0xdfde, 0xa31a, 0x2002,
        0x6a6b, 0x074b, 0x2002, 0x074b, 0x6a6b, 0x2002, 0x2002, 0x2002, 0x2002,
        0xd17c, 0xd17c, 0x2002, 0x8312, 0xdfde, 0x138d, 0x2002, 0x2853, 0x496b,
        0x2002, 0xc432, 0x6a6b, 0x2002, 0x2002, 0x2002, 0xd17c, 0xdfde, 0xdfde,
        0xd17c, 0x2002, 0x3bc6, 0x5cc6, 0x2002, 0xe63a, 0x6a6b, 0x2002, 0x8322,
        0x6a6b, 0x6112, 0x2002, 0x2002, 0xd17c, 0xdfde, 0xdfde, 0xd17c, 0x2002,
        0xf9b5, 0x5cc6, 0x2002, 0xc53a, 0x6a6b, 0x2002, 0x8322, 0x6a6b, 0x6112,
        0x2002, 0x2002, 0x2002, 0xd17c, 0xd17c, 0x2002, 0x2002, 0x683b, 0x683b,
        0x2002, 0x410a, 0xa42a, 0x2002, 0x400a, 0xe642, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x6112, 0x6112, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0xe642,
        0x6a6b, 0x6a6b, 0x6a6b, 0x6a6b, 0x074b, 0x621a, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x400a, 0x8322, 0x8322,
        0xc432, 0x074b, 0x6a6b, 0x6a6b, 0x285b, 0x410a, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0xa432, 0x6a6b, 0x6a6b, 0x8322, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x0d5c, 0xdfde, 0xdfde, 0xbfd6, 0x759d, 0xe522, 0x2002,
        0x400a, 0x495b, 0x6a6b, 0x8322, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xc422, 0xd17c, 0xf284, 0xf9b5, 0xdfde, 0xdfde, 0x5595, 0x2002, 0x2002,
        0x495b, 0x6a6b, 0x410a, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x4102, 0x148d, 0xdfde, 0x1abe, 0x2002, 0x400a, 0x6a6b,
        0x285b, 0x2002, 0x2002, 0x2002, 0x2002, 0x683b, 0x5cc6, 0x5cc6, 0x138d,
        0xa31a, 0x2002, 0x0d5c, 0xdfde, 0x5595, 0x2002, 0xa432, 0x6a6b, 0x621a,
        0x2002, 0x2002, 0x2002, 0x683b, 0xf9b5, 0x3bc6, 0xdfde, 0xdfde, 0xaa4b,
        0x2002, 0x148d, 0xdfde, 0xe522, 0x2002, 0x6a6b, 0x074b, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x8312, 0x7cce, 0xdfde, 0xa31a, 0x4102,
        0xdfde, 0x759d, 0x2002, 0x074b, 0x6a6b, 0x2002, 0x2002, 0x2002, 0x2002,
        0xd17c, 0xd17c, 0x2002, 0x8312, 0xdfde, 0x138d, 0x2002, 0xf9b5, 0xbed6,
        0x2002, 0xc432, 0x6a6b, 0x2002, 0x2002, 0x2002, 0xd17c, 0xdfde, 0xdfde,
        0xd17c, 0x2002, 0x3bc6, 0x5cc6, 0x2002, 0xf284, 0xdfde, 0x2002, 0x8322,
        0x6a6b, 0x6112, 0x2002, 0x2002, 0xd17c, 0xdfde, 0xdfde, 0xd17c, 0x2002,
        0xf9b5, 0x5cc6, 0x2002, 0xd17c, 0xdfde, 0x2002, 0x8322, 0x6a6b, 0x6112,
        0x2002, 0x2002, 0x2002, 0xd17c, 0xd17c, 0x2002, 0x2002, 0x683b, 0x683b,
        0x2002, 0xc422, 0x0d5c, 0x2002, 0x400a, 0xe642, 0x2002, 0x2002,
    },
    {
        0x2002, 0x2002, 0x052b, 0x052b, 0x610a, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x148d,
        0xdfde, 0xdfde, 0xdfde, 0xdfde, 0x97a5, 0x483b, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x8212, 0xeb53, 0x8943,
        0x6f6c, 0x97a5, 0xdfde, 0xdfde, 0x3bbe, 0xc41a, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x4e6c, 0xdfde, 0xdfde, 0xaa4b, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x0d5c, 0xdfde, 0xdfde, 0xbfd6, 0x759d, 0xe522, 0x2002,
        0x8212, 0x5cc6, 0xdfde, 0xaa4b, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0xc422, 0xd17c, 0xf284, 0xf9b5, 0xdfde, 0xdfde, 0x5595, 0x2002, 0x2002,
        0x5cc6, 0xdfde, 0xc41a, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0x2002,
        0x2002, 0x2002, 0x4102, 0x148d, 0xdfde, 0x1abe, 0x2002, 0x8212, 0xdfde,
        0x3bbe, 0x2002, 0x2002, 0x2002, 0x2002, 0x683b, 0x5cc6, 0x5cc6, 0x138d,
        0xa31a, 0x2002, 0x0d5c, 0xdfde, 0x5595, 0x2002, 0x4e6c, 0xdfde, 0x483b,
        0x2002, 0x2002, 0x2002, 0x683b, 0xf9b5, 0x3bc6, 0xdfde, 0xdfde, 0xaa4b,
        0x2002, 0x148d, 0xdfde, 0xe522, 0x2002, 0xdfde, 0x97a5, 0x2002, 0x2002,
        0x2002, 0x2002, 0x2002, 0x2002, 0x8312, 0x7cce, 0xdfde, 0xa31a, 0x4102,
        0xdfde, 0x759d, 0x2002, 0x97a5, 0xdfde, 0x2002, 0x2002, 0x2002, 0x2002,
        0xd17c, 0xd17c, 0x2002, 0x8312, 0xdfde, 0x138d, 0x2002, 0xf9b5, 0xbed6,
        0x2002, 0x6f6c, 0xdfde, 0x610a, 0x2002, 0x2002, 0xd17c, 0xdfde, 0xdfde,
        0xd17c, 0x2002, 0x3bc6, 0x5cc6, 0x2002, 0xf284, 0xdfde, 0x2002, 0x8943,
        0xdfde, 0x052b, 0x2002, 0x2002, 0xd17c, 0xdfde, 0xdfde, 0xd17c, 0x2002,
        0xf9b5, 0x5cc6, 0x2002, 0xd17c, 0xdfde, 0x2002, 0xeb53, 0xdfde, 0x052b,
        0x2002, 0x2002, 0x2002, 0xd17c, 0xd17c, 0x2002, 0x2002, 0x683b, 0x683b,
        0x2002, 0xc422, 0x0d5c, 0x2002, 0x8212, 0x148d, 0x2002, 0x2002,
    },
};

struct framedata_t {
    enum {
        center,
        highest,
        average,
        lowest,
    };
    uint16_t temp[4];
    bool subpage;
    uint16_t pixel_raw[frame_width * frame_height];
    uint8_t low_x;
    uint8_t low_y;
    uint8_t high_x;
    uint8_t high_y;
    std::string getJsonData(void) const;
};

struct value_smooth_t {
    int32_t exec(int32_t src, int32_t margin);
    void set(int32_t default_value);

   private:
    int _add = 0;
    int32_t _target;
    int32_t _current;
};

// グラフ表示のためのデータ蓄積用構造体
struct graph_data_t {
    // 要素数は256固定とする。インデクスをuint8_tとすることで履歴の記録を簡素化する
    static constexpr const uint16_t data_len = 256;
    uint16_t* temp_arrays[4]                 = {
        nullptr,
    };
    uint8_t current_idx = 0;
};

extern uint8_t config_save_countdown;

struct itext_t {
    virtual const char* get(void) const = 0;
    inline operator const char*(void) const {
        return get();
    }
};

struct single_text_t : public itext_t {
    const char* text;
    constexpr single_text_t(const char* t1) : text{t1} {
    }
    const char* get(void) const override {
        return text;
    }
};

struct localize_text_t : public itext_t {
    static uint8_t localize_index;
    const char* texts[3];
    constexpr localize_text_t(const char* t1, const char* t2, const char* t3)
        : texts{t1, t2, t3} {
    }
    const char* get(void) const override {
        return texts[localize_index];
    }
};

// 各種動作設定プロパティ用クラス
class config_property_base_t {
   public:
    virtual const localize_text_t* getName(void) {
        return nullptr;
    }
    virtual const char* getText(void)   = 0;
    virtual int32_t get(void) const     = 0;
    virtual bool set(const int32_t src) = 0;
    virtual bool add(int32_t val) {
        return set(get() + val);
    }
};

template <typename T>
class config_property_enum_t : public config_property_base_t {
   protected:
    const char* const* _text_tbl;
    T _value;
    const T _maximum;
    void (*_change_func)(T value);

   public:
    config_property_enum_t(const char* const* text_tbl, T value, T maximum,
                           void (*change_func)(T) = nullptr)
        : _text_tbl{text_tbl},
          _value{value},
          _maximum{maximum},
          _change_func{change_func} {
    }

    T get_enum(void) const {
        return _value;
    }
    inline operator T(void) const {
        return get_enum();
    }
    T operator=(T src) {
        set(src);
        return get_enum();
    }
    const char* getText(void) override {
        return _text_tbl ? _text_tbl[get()] : "";
    }
    int32_t get(void) const override {
        return _value;
    }
    bool set(const int32_t src) override {
        T v         = (T)((src < 0)                ? 0
                          : (src < (_maximum - 1)) ? src
                                                   : (_maximum - 1));
        bool result = (_value != v);
        if (result) {
            config_save_countdown = 255;
            _value                = v;
        }
        if (_change_func) {
            _change_func(v);
        }
        return result;
    }
    bool add(int32_t val) override {
        return set((val + _maximum + get()) % _maximum);
    }
};

template <typename T>
class config_property_localize_enum_t : public config_property_base_t {
   protected:
    const localize_text_t _name;
    const localize_text_t* _text_tbl;
    T _default;
    T _value;
    const T _maximum;
    void (*_change_func)(T value);

   public:
    config_property_localize_enum_t(const localize_text_t name,
                                    const localize_text_t* text_tbl, T value,
                                    T maximum, void (*change_func)(T) = nullptr)
        : _name{name},
          _text_tbl{text_tbl},
          _default{value},
          _value{value},
          _maximum{maximum},
          _change_func{change_func} {
    }

    bool setDefault(void) {
        return set(_default);
    }
    T get_enum(void) const {
        return _value;
    }
    inline operator T(void) const {
        return get_enum();
    }
    T operator=(T src) {
        set(src);
        return get_enum();
    }
    const localize_text_t* getName(void) override {
        return &_name;
    }
    const char* getText(void) override {
        return _text_tbl[get()].get();
    }
    const char* getText(size_t idx) {
        return _text_tbl[idx].get();
    }
    int32_t get(void) const override {
        return _value;
    }
    bool set(const int32_t src) override {
        T v         = (T)((src < 0)                ? 0
                          : (src < (_maximum - 1)) ? src
                                                   : (_maximum - 1));
        bool result = (_value != v);
        if (result) {
            config_save_countdown = 255;
            _value                = v;
        }
        if (_change_func) {
            _change_func(v);
        }
        return result;
    }
    bool add(int32_t val) override {
        return set((val + _maximum + get()) % _maximum);
    }
};

template <typename T>
class config_property_value_t : public config_property_base_t {
   protected:
    void (*_text_func)(char* text_buf, size_t buf_len, T value);
    T _value;
    const T _minimum;
    const T _maximum;
    const T _step;
    void (*_change_func)(T value);
    char _text_buf[16] = "";

   public:
    config_property_value_t(void (*text_func)(char*, size_t, T), T value,
                            T minimum, T maximum, T step,
                            void (*change_func)(T) = nullptr)
        : _text_func{text_func},
          _value{value},
          _minimum{minimum},
          _maximum{maximum},
          _step{step},
          _change_func{change_func} {
        _text_func(_text_buf, sizeof(_text_buf), value);
    }
    inline operator int32_t(void) const {
        return get();
    }
    int32_t operator=(int32_t src) {
        set(src);
        return get();
    }
    const char* getText(void) override {
        return _text_buf;
    }
    int32_t get(void) const override {
        return _value;
    }
    bool set(const int32_t src) override {
        T v         = (T)((src < _minimum)       ? _minimum
                          : (src < _maximum + 1) ? src
                                                 : _maximum + 1);
        bool result = (_value != v);
        if (result) {
            config_save_countdown = 255;
            _value                = (T)v;
        }
        _text_func(_text_buf, sizeof(_text_buf), v);
        if (_change_func) {
            _change_func(v);
        }
        return result;
    }
    bool add(int32_t val) override {
        auto range = _maximum - _minimum + 1;
        val        = (val * _step + get() + range - _minimum) % range;
        return set(val + _minimum);
    }
};

struct config_param_t {
    void saveNvs(void);
    void loadNvs(void);
    void loadDefault(void);
    void setEmissivity(uint8_t emissivity);
    void setTimeZoneSec(int32_t sec);
    void referenceModeChange(int add = 0);

    static constexpr const char* common_off_on_text[] = {"Off", "On"};

    enum net_running_mode_t {
        net_running_mode_offline,    // 0
        net_running_mode_cloud,      // 1
        net_running_mode_lan,        // 2
        net_running_mode_lan_cloud,  // 3
        net_running_mode_max,
    };
    // static constexpr const localize_text_t net_running_mode_text[] =
    // { { "Offline"     , "离线"     , "オフライン"  },
    //   { "Cloud Online", "云监控"   , "クラウド"    },
    //   { "LAN"         , "局域网"   , "LAN"         },
    //   { "LAN+Cloud"   , "局域网+云", "LAN+クラウド"},
    // };

    enum net_setup_mode_t {
        net_setup_mode_off,
        net_setup_mode_smartconfig,
        net_setup_mode_accesspoint,
        // net_wifi_mode_keep_connect,
        // net_wifi_mode_uploading,
        net_setup_mode_max,
    };
    // static constexpr const char* net_setup_mode_text[] = { "Off", "ESP TOUCH
    // APP", "AP mode", "Keep connection", "OnCloud only" };

    enum alarm_mode_t {
        alarm_mode_off,
        alarm_mode_lowtemp,
        alarm_mode_hightemp,
        alarm_mode_max,
    };
    // static constexpr const char* alarm_mode_text[] = { "Disable", "Lower",
    // "Higher" };

    enum alarm_reference_t {
        alarm_reference_highest,
        alarm_reference_lowest,
        alarm_reference_center,
        alarm_reference_average,
        alarm_reference_max,
    };
    // static constexpr const char* alarm_reference_text[] = { "Highest",
    // "Lowest", "Center", "Average" };
    /*
        enum alarm_behavior_t {
            alarm_behavior_off,
            alarm_behavior_beep,
            alarm_behavior_led,
            alarm_behavior_beep_led,
            alarm_behavior_max,
        };
        static constexpr const char* alarm_behavior_text[] = { "Off", "BEEP",
       "LED", "BEEP+LED" };
    */

    enum misc_cpuspeed_t {
        misc_cpuspeed_80,
        misc_cpuspeed_160,
        misc_cpuspeed_240,
        misc_cpuspeed_max,
    };
    // static constexpr const char* misc_cpuspeed_text[] = { "80MHz", "160MHz",
    // "240MHz" };
    static constexpr const uint8_t misc_cpuspeed_value[] = {80, 160, 240};

    enum sens_refreshrate_t {
        sens_refreshrate_0_5,
        sens_refreshrate_1,
        sens_refreshrate_2,
        sens_refreshrate_4,
        sens_refreshrate_8,
        sens_refreshrate_16,
        sens_refreshrate_32,
        sens_refreshrate_max,
    };
    // static constexpr const char* sens_refreshrate_text[] = { "0.5Hz", "1Hz",
    // "2Hz", "4Hz", "8Hz", "16Hz", "32Hz" };
    static constexpr const uint8_t sens_refreshrate_value[] = {0, 1, 2, 3,
                                                               4, 5, 6};

    enum sens_noisefilter_t {
        sens_noisefilter_off,
        sens_noisefilter_weak,
        sens_noisefilter_medium,
        sens_noisefilter_strong,
        sens_noisefilter_max,
    };
    // static constexpr const char* sens_noisefilter_text[] = { "Off", "Weak",
    // "Medium", "Strong" };
    static constexpr const uint8_t sens_noisefilter_value[] = {0, 4, 8, 12};

    enum sens_monitorarea_t {
        sens_monitorarea_16x16,
        sens_monitorarea_20x20,
        sens_monitorarea_24x24,
        sens_monitorarea_28x24,
        sens_monitorarea_30x24,
        sens_monitorarea_max,
    };
    // static constexpr const char* sens_monitorarea_text[] = { "16x16",
    // "20x20", "24x24", "28x24", "30x24" };
    static constexpr const uint8_t sens_monitorarea_value[] = {
        0x88u, 0xAAu, 0xCC, 0xEC, 0xFC};

    enum range_autoswitch_t {
        range_autoswitch_off,
        range_autoswitch_on,
        range_autoswitch_max,
    };

    enum misc_brightness_t {
        misc_brightness_low,
        misc_brightness_middle,
        misc_brightness_high,
        misc_brightness_max,
    };
    // static constexpr const char* misc_brightness_text[] = { "Low", "Middle",
    // "High" };
    static constexpr const uint8_t misc_brightness_value[] = {63, 100, 200};

    enum misc_language_t {
        misc_language_en,
        misc_language_cn,
        misc_language_ja,
        misc_language_max,
    };
    static constexpr const char* misc_language_text[] = {"English", "中文",
                                                         "日本語"};
    // static constexpr const lgfx::IFont* misc_language_value[] = {
    // &fonts::DejaVu12, &fonts::DejaVu18, &fonts::DejaVu24 }; static constexpr
    // const lgfx::IFont* misc_language_value[] = { &fonts::efontJA_14,
    // &fonts::efontJA_16, &fonts::efontJA_24 };
    static constexpr const lgfx::IFont* misc_language_value[] = {
        &fonts::efontCN_24, &fonts::efontCN_24, &fonts::efontJA_24};

    enum misc_pointer_t {
        misc_pointer_off,
        misc_pointer_point,
        misc_pointer_pointtxt,
        misc_pointer_max,
    };
    // static constexpr const char* misc_pointer_text[] = { "Off", "Point",
    // "Point+Value" };

    enum misc_volume_t {
        misc_volume_mute,
        misc_volume_small,
        misc_volume_normal,
        misc_volume_max,
    };
    // static constexpr const char* misc_volume_text[] = { "Mute", "Small",
    // "Normal" };
    static constexpr const uint8_t misc_volume_value[] = {0, 80, 160};

    // enum cloud_upload_t {
    //     cloud_upload_off,
    //     cloud_upload_on,
    //     cloud_upload_max,
    // };

    enum misc_color_t {
        misc_color_golden,
        misc_color_rainbow,
        misc_color_grayscale,
        misc_color_ironblack,
        misc_color_cam,
        misc_color_max,
    };

    enum cloud_interval_t {
        cloud_interval_5sec,
        cloud_interval_10sec,
        cloud_interval_30sec,
        cloud_interval_60sec,
        cloud_interval_120sec,
        cloud_interval_300sec,
        cloud_interval_600sec,
        cloud_interval_1800sec,
        cloud_interval_3600sec,
        cloud_interval_max,
    };
    static constexpr const uint16_t cloud_interval_value[] = {
        5, 10, 30, 60, 120, 300, 600, 1800, 3600};

    static void alarm_temperature_text_func(char* text_buf, size_t buf_len,
                                            uint16_t v) {
        snprintf(text_buf, buf_len, "%3.1fC", (float)v / 128 - 64);
    }

    static void sens_temperature_text_func(char* text_buf, size_t buf_len,
                                           int32_t v) {
        snprintf(text_buf, buf_len, "%3.1fC", (float)v / 128 - 64);
    }

    static void perf_emissivity_text_func(char* text_buf, size_t buf_len,
                                          uint8_t v) {
        snprintf(text_buf, buf_len, "%d %%", v);
    }

    static void uint8_t_text_func(char* text_buf, size_t buf_len, uint8_t v) {
        snprintf(text_buf, buf_len, "%d", v);
    }

    static void misc_backtofactory_text_func(char* text_buf, size_t buf_len,
                                             uint8_t v) {
        static constexpr const char* text = "Enter To Reset";
        text_buf                          = strcpy(text_buf, text);
    }

    static void misc_staff_text_func(char* text_buf, size_t buf_len,
                                     uint8_t v) {
        static constexpr const char* text = "View Info";
        text_buf                          = strcpy(text_buf, text);
    }

    const char net_apmode_pass[12] = "12341234";
    char net_apmode_ssid[16] =
        "T-Lite_xxxx";  // セットアップ時にMACアドレスを付与するためサイズに余裕を持たせておく
    const ip_addr_t dnsip = IPADDR4_INIT_BYTES(192, 168, 4, 1);
    const IPAddress net_apmode_ipaddr{192, 168, 4, 1};
    const IPAddress net_apmode_subnet{255, 255, 255, 0};

    static void net_running_mode_func(net_running_mode_t);
    static void misc_cpuspeed_func(misc_cpuspeed_t);
    static void sens_refreshrate_func(sens_refreshrate_t);
    static void sens_noisefilter_func(sens_noisefilter_t);
    static void perf_emissivity_func(uint8_t);
    static void range_temperature_func(int32_t);
    // static void net_wifi_mode_func(net_wifi_mode_t);
    static void misc_brightness_func(misc_brightness_t);
    static void misc_language_func(misc_language_t);
    static void misc_volume_func(misc_volume_t);
    static void misc_color_func(misc_color_t v);
    static void misc_backtofactory_func(uint8_t);

    config_property_localize_enum_t<net_running_mode_t> net_running_mode = {
        {"Running Mode", "运行模式", "動作モード"},
        (const localize_text_t[]){
            {"Offline", "离线", "オフライン"},
            {"Cloud Online", "云监控", "クラウド"},
            {"LAN", "局域网", "LAN"},
            {"LAN+Cloud", "局域网+云", "LAN+クラウド"},
        },
        net_running_mode_t::net_running_mode_offline,
        net_running_mode_t::net_running_mode_max,
        net_running_mode_func};

    config_property_localize_enum_t<net_setup_mode_t> net_setup_mode = {
        {"WiFi Setting", "WiFi设置", "WiFi設定"},
        (const localize_text_t[]){
            {"Off", "关闭AP", "オフ"},
            {"ESP TOUCH APP", "通过ESP TOUCH APP配置", "ESP TOUCHアプリ"},
            {"AP mode", "连接本机AP热点", "アクセスポイントモード"},
        },
        net_setup_mode_t ::net_setup_mode_off,
        net_setup_mode_t ::net_setup_mode_max};

    config_property_localize_enum_t<cloud_interval_t> cloud_interval = {
        {"Upload Interval", "上传间隔时间", "アップロード間隔"},
        (const localize_text_t[]){
            {"5Sec", "5秒", "5秒"},
            {"10Sec", "10秒", "10秒"},
            {"30Sec", "30秒", "30秒"},
            {"1Min", "1分", "1分"},
            {"2Min", "2分", "2分"},
            {"5Min", "5分", "5分"},
            {"10Min", "10分", "10分"},
            {"30Min", "30分", "30分"},
            {"1Hour", "1小时", "1時間"},
        },
        cloud_interval_t ::cloud_interval_30sec,
        cloud_interval_t ::cloud_interval_max};

    config_property_value_t<uint16_t> alarm_temperature = {
        alarm_temperature_text_func, (100 + 64) * 128, (-50 + 64) * 128,
        (350 + 64) * 128, 32};

    config_property_localize_enum_t<alarm_mode_t> alarm_mode = {
        {"Alarm Mode", "报警触发条件", "アラーム条件"},
        (const localize_text_t[]){
            {"Disable", "关闭报警", "無効"},
            {"Lower", "低于设定", "低温時"},
            {"Higher", "高于设定", "高温時"},
        },
        alarm_mode_t ::alarm_mode_hightemp,
        alarm_mode_t ::alarm_mode_max};

    config_property_localize_enum_t<alarm_reference_t> alarm_reference = {
        {"Reference", "触发范围", "参照温度"},
        (const localize_text_t[]){
            {"Highest", "最高温度", "最高温度"},
            {"Lowest", "最低温度", "最低温度"},
            {"Center", "中央温度", "中央温度"},
            {"Average", "平均温度", "平均温度"},
        },
        alarm_reference_t ::alarm_reference_highest,
        alarm_reference_t ::alarm_reference_max};

    config_property_localize_enum_t<sens_refreshrate_t> sens_refreshrate = {
        {"Refresh Rate", "刷新速度", "更新レート"},
        (const localize_text_t[]){
            {"0.5Hz", "0.5Hz", "0.5Hz"},
            {"1Hz", "1Hz", "1Hz"},
            {"2Hz", "2Hz", "2Hz"},
            {"4Hz", "4Hz", "4Hz"},
            {"8Hz", "8Hz", "8Hz"},
            {"16Hz", "16Hz", "16Hz"},
            {"32Hz", "32Hz", "32Hz"},
        },
        sens_refreshrate_t::sens_refreshrate_16,
        sens_refreshrate_t::sens_refreshrate_max,
        sens_refreshrate_func};

    config_property_localize_enum_t<sens_noisefilter_t> sens_noisefilter = {
        {"Noise Filter", "噪点过滤", "ノイズフィルタ"},
        (const localize_text_t[]){
            {"Off", "关闭", "無効"},
            {"Weak", "轻微", "弱"},
            {"Medium", "中等", "中"},
            {"Strong", "强", "強"},
        },
        sens_noisefilter_t::sens_noisefilter_medium,
        sens_noisefilter_t::sens_noisefilter_max,
        sens_noisefilter_func};

    config_property_localize_enum_t<sens_monitorarea_t> sens_monitorarea = {
        {"Monitor Area", "监视区", "監視エリア"},
        (const localize_text_t[]){
            {"16x16", "16x16", "16x16"},
            {"20x20", "20x20", "20x20"},
            {"24x24", "24x24", "24x24"},
            {"28x24", "28x24", "28x24"},
            {"30x24", "30x24", "30x24"},
        },
        sens_monitorarea_t::sens_monitorarea_30x24,
        sens_monitorarea_t::sens_monitorarea_max};

    config_property_value_t<uint8_t> sens_emissivity = {
        perf_emissivity_text_func, 98, 20, 100, 1, perf_emissivity_func};

    config_property_localize_enum_t<range_autoswitch_t> range_autoswitch = {
        {"Auto Range", "自动量程", "自動レンジ"},
        (const localize_text_t[]){
            {"Off", "关闭", "無効"},
            {"On", "打开", "有効"},
        },
        range_autoswitch_t::range_autoswitch_on,
        range_autoswitch_t::range_autoswitch_max};

    config_property_value_t<int32_t> range_temp_upper = {
        sens_temperature_text_func,
        (300 + 64) * 128,
        (-50 + 64) * 128,
        (350 + 64) * 128,
        32,
        range_temperature_func};

    config_property_value_t<int32_t> range_temp_lower = {
        sens_temperature_text_func,
        (0 + 64) * 128,
        (-50 + 64) * 128,
        (350 + 64) * 128,
        32,
        range_temperature_func};

    config_property_localize_enum_t<misc_cpuspeed_t> misc_cpuspeed = {
        {"CPU Clock", "CPU 主频", "CPU周波数"},
        (const localize_text_t[]){
            {"80MHz", "80MHz", "80MHz"},
            {"160MHz", "160MHz", "160MHz"},
            {"240MHz", "240MHz", "240MHz"},
        },
        misc_cpuspeed_t ::misc_cpuspeed_160,
        misc_cpuspeed_t ::misc_cpuspeed_max,
        misc_cpuspeed_func};

    config_property_localize_enum_t<misc_volume_t> misc_volume = {
        {"Sound Volume", "蜂鸣器音量", "ブザー音量"},
        (const localize_text_t[]){
            {"Mute", "关闭", "無音"},
            {"Small", "小", "小"},
            {"Normal", "正常", "標準"},
        },
        misc_volume_t ::misc_volume_normal,
        misc_volume_t ::misc_volume_max,
        misc_volume_func};

    config_property_localize_enum_t<misc_brightness_t> misc_brightness = {
        {"LCD Brightness", "屏幕亮度", "画面の明るさ"},
        (const localize_text_t[]){
            {"Low", "暗", "低輝度"},
            {"Middle", "中等", "標準"},
            {"High", "亮", "高輝度"},
        },
        misc_brightness_t ::misc_brightness_middle,
        misc_brightness_t ::misc_brightness_max,
        misc_brightness_func};

    config_property_localize_enum_t<misc_pointer_t> misc_pointer = {
        {"Pointer", "光标", "ポインタ"},
        (const localize_text_t[]){
            {"Off", "关闭", "無し"},
            {"Point", "点", "点"},
            {"Point+Value", "点+数值", "点+値"},
        },
        misc_pointer_t ::misc_pointer_pointtxt,
        misc_pointer_t ::misc_pointer_max};

    config_property_localize_enum_t<misc_color_t> misc_color = {
        {"Color", "色样", "色"},
        (const localize_text_t[]){
            {"Golden", "金色", "金色"},
            {"Rainbow", "彩虹", "虹色"},
            {"Grayscale", "灰度", "グレー"},
            {"IronBlack", "铁黑", "黒鉄"},
            {"Cam", "摄像头", "カメラ"},
        },
        misc_color_t ::misc_color_golden,
        misc_color_t ::misc_color_max,
        misc_color_func};

    config_property_localize_enum_t<misc_language_t> misc_language = {
        {"Language", "Language", "Language"},
        (const localize_text_t[]){
            {"English", "英文", "英語"},
            {"Chinise", "中文", "中国語"},
            {"Japanese", "日文", "日本語"},
        },
        misc_language_t ::misc_language_en,
        misc_language_t ::misc_language_max,
        misc_language_func};

    // config_property_enum_t<misc_language_t>    misc_language     = {
    // misc_language_text          , misc_language_t   ::misc_language_en ,
    // misc_language_t   ::misc_language_max, misc_language_func };
    config_property_value_t<uint8_t> net_jpg_quality = {uint8_t_text_func, 60,
                                                        1, 100, 1};
    config_property_value_t<uint8_t> misc_layout     = {uint8_t_text_func, 1, 0,
                                                    255, 1};
    config_property_value_t<uint8_t> misc_backtofactory = {
        misc_backtofactory_text_func, 0, 0, 0, 0, misc_backtofactory_func};
    config_property_value_t<uint8_t> misc_staff = {misc_staff_text_func, 0, 0,
                                                   1, 1};
    // config_property_enum_t<cloud_upload_t>     cloud_upload      = {
    // common_off_on_text          , cloud_upload_t    ::cloud_upload_off ,
    // cloud_upload_t    ::cloud_upload_max };

    std::string cloud_token;

    int32_t oncloud_timezone_sec;
    // uint16_t oncloud_interval = 30;
    // bool oncloud_switch       = false;
    // wifi_mode_t net_wifi_mode = wifi_mode_t::WIFI_MODE_NULL;
    // bool net_webserver = false;
    // uint8_t misc_rotation = 1;

    bool in_config_mode     = false;
    uint8_t in_pause_state  = 0;
    bool in_rangehold_state = false;
    // uint8_t show_reference_name = 0;
    uint8_t request_wifi_state = 0;
};

struct draw_param_t : public config_param_t {
    void setup(LovyanGFX* gfx_, framedata_t* frame_array_, int frameindex);
    void setFont(const m5gfx::IFont* font_);
    void setColorTable(const uint16_t* tbl);
    void setColorTable(size_t idx);
    bool update(int frameindex);
    bool range_update(void);

    const m5gfx::IFont* font;
    const framedata_t* frame;
    const uint16_t* color_map = color_map_table[0];
    graph_data_t graph_data;
    // static constexpr const uint16_t graph_temp_len = 240;
    // uint16_t* graph_temp_arrays[4] = { nullptr, };
    int32_t temp_diff;
    uint16_t background_color = 0;
    uint8_t update_count      = 0;
    uint8_t modify_count      = 0;
    uint32_t draw_count       = 0;
    int8_t battery_state;
    int8_t battery_level;
    uint8_t font_height     = 8;
    bool oncloud_conf_valid = false;
    uint8_t macaddr[8];

    enum cloud_status_t {
        cloud_disable,
        cloud_timerwait,
        cloud_connection,
        cloud_uploading,
        cloud_complete,
        cloud_error,
    };
    cloud_status_t cloud_status;

    uint16_t cloud_countdown_sec = 0;  // アップロードまでの残り秒数
    std::string sys_ssid;              // 利用するSSID
    std::string net_tmp_ssid;  // APモードで設定のために一時的に利用するSSID
    std::string
        net_tmp_pwd;  // APモードで設定のために一時的に利用するパスワード
    std::string net_ap_url;    // APモードアクセス用URL
    std::string net_url_mdns;  // mDNS名アクセス用URL
    std::string net_url_ip;    // mDNS名アクセス用URL
    std::string net_hostname;  // T-Lite_xxxx.local
    std::string cloud_url;
    IPAddress cloud_ip;

   protected:
    const framedata_t* _frame_array;
    uint8_t _prev_frameindex;

    value_smooth_t _lowest_value;
    value_smooth_t _highest_value;
};
